/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.txweb.view;

import com.jspx.boot.EnvFactory;
import com.jspx.boot.sign.LanguageRes;
import com.jspx.txweb.IUserSession;
import com.jspx.txweb.dao.IpLocationDAO;
import com.jspx.txweb.table.DownloadFileClient;
import com.jspx.txweb.table.IpLocation;
import org.slf4j.Logger;
import com.jspx.boot.environment.Environment;
import org.slf4j.LoggerFactory;
import com.jspx.boot.sign.YesNoType;
import com.jspx.sioc.annotation.Ref;
import com.jspx.txweb.action.UploadFileAction;
import com.jspx.txweb.annotation.HttpMethod;
import com.jspx.txweb.annotation.Safety;
import com.jspx.txweb.dao.UploadFileDAO;
import com.jspx.txweb.support.ActionSupport;
import com.jspx.txweb.table.IUploadFile;
import com.jspx.txweb.util.RequestUtil;
import com.jspx.txweb.util.TXWebUtil;
import com.jspx.utils.*;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * Created with IntelliJ IDEA.
 * User: chenyuan
 * Date: 12-11-8
 * Time: 下午7:44
 * java 控制下载的方式
 * 有两个参数可以带
 * s=1  表示输出会进行统计
 * d=1   表示下载模，式会带后缀名称输出下载
 */
@HttpMethod(caption = "下载文件")
public class DownloadFileView extends ActionSupport {
    private static final Logger log = LoggerFactory.getLogger(DownloadFileView.class);
    private String[] stopArray = new String[]{"sourceforge.net", "xunlei", "flashget", "dirbuster", "nikto", "sqlmap", "whatweb", "openvas", "jbrofuzz", "libwhisker", "webshag", "baiduspider", "googlebot", "yahoo", "msnbot", "scooter", "docin", "douban", "eapoo", "doc88", "baidu", "renrendoc"};
    final private static int bufferSize = 1024;
    final private static float version = StringUtil.toFloat(System.getProperty("java.vm.specification.version"));
    private static int downloadUser = 0;

    public DownloadFileView() {

    }

    ///////////////载入IOC DAO 对象 begin
    private UploadFileDAO uploadFileDAO;
    //@Ref(name = Environment.uploadFileDAO)
    public void setUploadFileDAO(UploadFileDAO uploadFileDAO) {
        this.uploadFileDAO = uploadFileDAO;
    }
    ///////////////载入IOC DAO 对象 end

    private IpLocationDAO ipLocationDAO;
    @Ref(name = Environment.ipLocationDAO)
    public void setIpLocationDAO(IpLocationDAO ipLocationDAO) {
        this.ipLocationDAO = ipLocationDAO;
    }


    public String[] getStopArray() {
        return stopArray;
    }

    @Safety(request = false)
    public void setStopArray(String[] stopArray) {
        this.stopArray = stopArray;
    }


    public String execute() throws Exception {
        if (RequestUtil.isPirated(request)) {
            addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.notAllowedExternalLinks));
            TXWebUtil.print(language.getLang(LanguageRes.notAllowedExternalLinks), TXWebUtil.htmlType, response);
            return NONE;
        }

        if (config.getInt(Environment.openSite) == YesNoType.NO) {
            addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.closeSite));
            TXWebUtil.print(language.getLang(LanguageRes.closeSite), TXWebUtil.htmlType, response);
            return NONE;
        }

        String userAgent = request.getHeader(RequestUtil.requestUserAgent);
        if (StringUtil.isNULL(userAgent)) {
            TXWebUtil.print(language.getLang(LanguageRes.closeSite), TXWebUtil.htmlType, response);
            return NONE;
        }

        userAgent = userAgent.toLowerCase();
        for (String stop : stopArray) {
            if (userAgent.contains(stop)) {
                TXWebUtil.print(language.getLang(LanguageRes.closeSite), TXWebUtil.htmlType, response);
                return NONE;
            }
        }

        int maxDownloader = config.getInt(Environment.maxDownloader, 100);
        if (downloadUser > maxDownloader) {
            TXWebUtil.print(language.getLang(LanguageRes.notAllowedExceedWaitMaxDownloader) + "," + maxDownloader, TXWebUtil.htmlType, response);
            return NONE;
        }

        long id = StringUtil.toLong(getEnv(Key_ActionName));
        Object uploadFileObject = uploadFileDAO.get(uploadFileDAO.getClassType(), id);
        if (uploadFileObject == null) {
            addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.fileNotFind));
            TXWebUtil.print(language.getLang(LanguageRes.fileNotFind), TXWebUtil.htmlType, response);
            return NONE;
        }

        IUploadFile uploadFile = (IUploadFile) uploadFileObject;
        //载入原图 begin
        if (getBoolean("p"))
        {
            if (uploadFile.getPid()>0) uploadFileObject = uploadFileDAO.get(uploadFileDAO.getClassType(), uploadFile.getPid());
            if (uploadFileObject == null)
            {
                addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.fileNotFind));
                TXWebUtil.print(language.getLang(LanguageRes.fileNotFind), TXWebUtil.htmlType, response);
                return NONE;
            }
            uploadFile = (IUploadFile)uploadFileObject;
        }
        //载入原图 end


        File fileName = UploadFileAction.getUploadFile(config, uploadFile.getFileName());
        if (fileName == null || !fileName.exists() || !fileName.isFile() || !fileName.canRead()) {
            addFieldInfo(Environment.warningInfo, language.getLang(LanguageRes.fileNotFind) + "," + uploadFile.getFileName());
            boolean debug = EnvFactory.getEnvironmentTemplate().getBoolean(Environment.logJspxDebug);
            if (debug)
                TXWebUtil.print(language.getLang(LanguageRes.fileNotFind) + "," + fileName, TXWebUtil.htmlType, response);
            else
                TXWebUtil.print(language.getLang(LanguageRes.fileNotFind), TXWebUtil.htmlType, response);
            return NONE;
        }

        if (getBoolean("s"))
        {
            uploadFile.setDownTimes(uploadFile.getDownTimes() + 1);
            uploadFileDAO.update(uploadFileObject, new String[]{"downTimes"});

            DownloadFileClient downloadFileClient = new DownloadFileClient();
            downloadFileClient.setBrowser(RequestUtil.getBrowser(request));
            downloadFileClient.setFid(uploadFile.getId());
            downloadFileClient.setSystem(RequestUtil.getSystem(request));
            downloadFileClient.setNetType(RequestUtil.getNetType(request));
            downloadFileClient.setUrl(request.getRequestURL().toString());
            //downloadFileClient.setLocation();  统计的时候在放入，在这里放入性能低下
            IpLocation ipLocation = ipLocationDAO.getIpLocation(getRemoteAddr());
            downloadFileClient.setLocation(ipLocation.getCity() + " " + ipLocation.getCountry());
            IUserSession userSession = (IUserSession) getUserSession();
            if (userSession!=null)
            {
                downloadFileClient.setPutUid(userSession.getUid());
                downloadFileClient.setPutName(userSession.getName());
            } else {
                downloadFileClient.setPutUid(Environment.GUEST_ID);
                downloadFileClient.setPutName(Environment.GUEST_NAME);
            }
            downloadFileClient.setIp(getRemoteAddr());
            downloadFileClient.setNamespace(uploadFileDAO.getNamespace());
            uploadFileDAO.save(downloadFileClient);
        }

        String fileType = FileUtil.getTypePart(fileName.getName());
        String contentType = null;
        if (version >= 1.7)
            contentType = Files.probeContentType(Paths.get(fileName.getAbsolutePath()));
        else {
            //为了兼容 jdk 1.6
            if ("mp4".equalsIgnoreCase(fileType)) {
                contentType = "video/mpeg4";
            } else if ("bt".equalsIgnoreCase(fileType)) {
                contentType = "application/x-bittorrent";
            } else if ("swftools".equalsIgnoreCase(fileType)) {
                contentType = "application/swftools";
            } else if ("xls".equalsIgnoreCase(fileType)) {
                contentType = "application/vnd.ms-excel";
            } else if ("doc".equalsIgnoreCase(fileType) || "docx".equalsIgnoreCase(fileType)) {
                contentType = "application/msword";
            } else if ("mdb".equalsIgnoreCase(fileType)) {
                contentType = "application/msaccess";
            } else if ("ppt".equalsIgnoreCase(fileType)) {
                contentType = "application/x-ppt";
            } else if ("xml".equalsIgnoreCase(fileType)) {
                contentType = "application/xml";
            } else if ("txt".equalsIgnoreCase(fileType) || "htm".equalsIgnoreCase(fileType) || "html".equalsIgnoreCase(fileType)) {
                contentType = "text/html";
            } else if ("zip".equalsIgnoreCase(fileType)) {
                contentType = "application/x-zip-compressed";
            } else if ("rar".equalsIgnoreCase(fileType)) {
                contentType = "application/x-rar-compressed";
            } else if (FileSuffixUtil.isImageSuffix(fileType)) {
                contentType = "image/" + fileType;
            }  else if ("js".equalsIgnoreCase(fileType)) {
                contentType = "application/x-javascript";
            }else {
                contentType = "application/msword";
            }
        }
        if (contentType==null)
        {
            contentType = "application/octet-stream";
        }
        response.reset();

        response.setHeader("framework", Environment.frameworkName + " " + Environment.version);
        response.setContentType(contentType);
        response.setBufferSize(bufferSize);
        response.setCharacterEncoding(config.get("encode", Environment.defaultEncode));
        if (getBoolean("d"))
        {
            response.setHeader(RequestUtil.requestContentDisposition, "attachment;filename=d" + id + "." + fileType);
        } else if (!FileSuffixUtil.isImageSuffix(fileType)){
            response.setHeader(RequestUtil.requestContentDisposition, "attachment;filename=a" + id + "." + fileType);
        }
        //-----------------------------------------------------
        downloadUser++;
        try {
            if (config.getInt(Environment.downloadType) == 1) {
                singleDownFile(fileName);
            } else {
                manyDownFile(fileName);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ERROR;
        } finally {
            downloadUser--;
        }
        return NONE;
    }

    private void singleDownFile(File file) throws IOException {
        ServletOutputStream out = response.getOutputStream();
        FileInputStream fin = new FileInputStream(file);
        byte[] bytes = new byte[bufferSize];
        long fileLength = file.length();
        response.setHeader(RequestUtil.requestContentLength, Long.toString(fileLength));
        int count;
        if (fileLength > 0)
            try {
                while ((count = fin.read(bytes)) > 0) {
                    out.write(bytes, 0, count);
                }
                out.close();
            } catch (Exception e) {
                log.error(file.getAbsolutePath(),e);
                out.flush();
                out.close();
                fin.close();
            }
    }

    private void manyDownFile(File file) throws IOException {
        long l = file.length();
        long p = 0;

        response.setHeader(RequestUtil.requestAcceptRanges, "bytes");
        if (request.getHeader("Range") != null) {
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            String sClient = request.getHeader("Range");

            if (sClient != null) {
                sClient = StringUtil.trim(StringUtil.substringAfter(sClient, "bytes"));
                if (sClient.contains("-"))
                    sClient = StringUtil.substringBefore(sClient, "-");
                p = Long.parseLong(StringUtil.getNumber(sClient));
            }
        }

        response.setHeader(RequestUtil.requestContentLength, Long.toString(l - p));
        if (p != 0) {

            response.setHeader(RequestUtil.requestContentRange, "bytes " + Long.toString(p) + "-" + Long.toString(l - 1) + "/" + Long.toString(l));
        }
        int count;
        byte[] bytes = new byte[bufferSize];
        FileInputStream fin = new FileInputStream(file);
        ServletOutputStream out = response.getOutputStream();
        try {

            if (p > -1) p = fin.skip(p);
            while ((count = fin.read(bytes)) > 0) {
                out.write(bytes, 0, count);
            }
            out.flush();
        } catch (Exception e) {
            log.error(file.getAbsolutePath(),e);
        } finally {
            fin.close();
        }
    }
}